// $Id$
package de.servicezombie.cxf;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.cxf.binding.xml.interceptor.XMLFaultOutInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.interceptor.StaxOutEndingInterceptor;
import org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor;
import org.apache.cxf.jaxrs.utils.JAXRSUtils;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageContentsList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.servicezombie.pub.r1.CommonRestResponse;

// CK quellcode von hier: 
//  - http://cxf.547215.n5.nabble.com/Handling-exceptions-thrown-by-interceptors-for-rest-calls-td4300713.html
//  - http://cxf.547215.n5.nabble.com/attachment/4306638/0/RestFaultOutInterceptor.java

public class AttachRestResponseFaultInterceptor extends JAXRSOutInterceptor {

	private static final Logger log = LoggerFactory.getLogger(AttachRestResponseFaultInterceptor.class);
	
	private static final Set<Class<?>> wrapperBlacklist = new HashSet<Class<?>>();
	static {
		wrapperBlacklist.add(CommonRestResponse.class);
	}

	public AttachRestResponseFaultInterceptor() {
		getBefore().add(LoggingOutInterceptor.class.getName());
		
		// for xml, this downstream interceptor caused an exception- therefore
		// standing before it so that I can remove it from the chain
		getBefore().add(XMLFaultOutInterceptor.class.getName());
		
		// for json, this downstream interceptor caused an exception- therefore
		// standing before it so that I can remove it from the chain
		getBefore().add(StaxOutEndingInterceptor.class.getName());
	}

	public void handleMessage(Message message) throws Fault {
		if (log.isDebugEnabled()) {
			log.debug("handleMessage: >> " + message);
		}
		
		WebserviceTemplate template = new WebserviceTemplateFactory().build();
		CommonRestResponse<?> wrapper = template.getWebserviceResponse();

		Exception ex = message.getContent(Exception.class);
		if (ex == null)
			return;

		// CK I'm not sure if JAXRSUtils is useful here
		if (ex instanceof Fault) {
			wrapper.getSys().setErrorContext(ex.getCause());
			JAXRSUtils.convertFaultToResponse(ex.getCause(), message.getExchange().getInMessage());
		}
		else {
			wrapper.getSys().setErrorContext(ex);
			JAXRSUtils.convertFaultToResponse(ex, message.getExchange().getInMessage());
		}

		message.setContent(List.class, new MessageContentsList(wrapper));

		// To avoid the null pointer from
		// JAXBElementProvider.getAttachments(...) , set out message on the
		// exchange
		message.getExchange().setOutMessage(message.getExchange().getOutFaultMessage());
		
		// let JAXRSOutInterceptor do the serialization
		super.handleMessage(message);

		hideExceptionInInterceptorChain(message);
	}

	private void hideExceptionInInterceptorChain(Message message) {
		// remove 2 culprits from the chain so as to use logging or other
		// interceptors downstrean
		Iterator<Interceptor<? extends Message>> chainIterator = message
				.getInterceptorChain().iterator();
		while (chainIterator.hasNext()) {
			Interceptor<? extends Message> interceptor = chainIterator.next();
			// removing for xml
			if (interceptor instanceof XMLFaultOutInterceptor) {
				message.getInterceptorChain().remove(
						(XMLFaultOutInterceptor) interceptor);

			}
			// removing for json
			if (interceptor instanceof StaxOutEndingInterceptor) {
				message.getInterceptorChain().remove((StaxOutEndingInterceptor) interceptor);

			}
		}
	}

}
